package com.ideaaedi.component.decompile.cfr;

import org.apache.commons.lang3.StringUtils;
import org.benf.cfr.reader.api.ClassFileSource;
import org.benf.cfr.reader.bytecode.analysis.parse.utils.Pair;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

/**
 * 待反编译的字节码
 *
 * @author JustryDeng
 * @since 2021/9/23 23:02:53
 */
public class ClassBytesSource implements ClassFileSource {
    
    /**
     * .class字节码容器<br><br>
     * key - 字节码唯一key(可以是uuid，也可以是全类名，保证唯一即可)<br>
     * value - 字节码
     */
    private final Map<String, byte[]> classProvider;
    
    /**
     * 路径映射map<br>
     * <ul>
     *     <li>key - {@link ClassBytesSource#informAnalysisRelativePathDetail}方法的参数classFilePath</li>
     *     <li>value - {@link ClassBytesSource#informAnalysisRelativePathDetail}方法的参数usePath</li>
     * </ul>
     */
    private final Map<String, String> pathMapping = new HashMap<>(8);
    
    public ClassBytesSource(Map<String, byte[]> classProvider) {
        Objects.requireNonNull(classProvider, "classProvider cannot be null.");
        this.classProvider = classProvider;
    }
    
    /**
     * usePath即，<code>CfrDriver#analyse(usePathList)</code>中的usePath，根据本人封装的工
     * 具类{@link CfrDecompiler}中的逻辑， 即形如：35faa0a32fd3451498da283e0d3d993e.class <br><br>
     *
     *
     * classFilePath即，usePath对应字节码所代表类的类文件名，
     * 形如：com/szlzcl/jdk8feature/OptionalTests.class
     *
     */
    @Override
    public void informAnalysisRelativePathDetail(String usePath, String classFilePath) {
        if (StringUtils.isAnyBlank(usePath, classFilePath)) {
            return;
        }
        if (usePath.equals(classFilePath)) {
            return;
        }
        pathMapping.put(classFilePath, usePath);
    }
    
    @Override
    public Collection<String> addJar(String jarPath) {
        return new ArrayList<>(4);
    }
    
    /**
     * classFilePath形如： com/szlzcl/jdk8feature/OptionalTests
     */
    @Override
    public String getPossiblyRenamedPath(String classFilePath) {
        if (StringUtils.isBlank(classFilePath)) {
            return classFilePath;
        }
        String usePath = pathMapping.get(classFilePath + ".class");
        if (StringUtils.isNotBlank(usePath)) {
            return usePath;
        }
        return classFilePath;
    }
    
    /**
     * path形如： com/szlzcl/jdk8feature/OptionalTests.class
     */
    @Override
    public Pair<byte[], String> getClassFileContent(String path) {
        byte[] classBytes = classProvider.get(path);
        return Pair.make(classBytes, path);
    }
}
